package com.andfo.testframework;

import com.jcraft.jsch.*;

import javax.swing.*;
import java.io.InputStream;
import java.util.Map;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Very simple class used to execute commands via ssh
 */
public class SshExec {

    private String user;
    private String password;
    private String host;

    JSch jsch = new JSch();
    Session session;

    private static Log log = LogFactory.getLog(SshExec.class);

    private SshExec(String user, String password, String host) {
        this.user = user;
        this.password = password;
        this.host = host;

        log.info("Creating SSH Client");
        log.debug("* User:" + user);
        log.debug("* Password:" + password);
        log.debug("* Host:" + host);
    }

    // Keep a list of all connections in order for effective reuse
    private static Map<String, SshExec> sshExecList = new HashMap<String, SshExec>();

    public static SshExec getConnection(String user, String password, String host) {
        String key = user + '|' + password + '|' + host;
        if(!sshExecList.containsKey(key)) {
            sshExecList.put(key, new SshExec(user, password, host));
        }
        return sshExecList.get(key);
    }

    private void open() {
        try {
            log.info("Connecting using ssh");
            session = jsch.getSession(user, host, 22);
            session.setConfig("StrictHostKeyChecking", "no");
            session.setPassword(password);
            session.connect();
        } catch (Exception e) {
            log.error("Error while opening connection", e);
            throw new RuntimeException();
        }
    }


    public synchronized String exec(String command) {
        try {

            if(session == null || !session.isConnected()) {
                open();
            }

            log.info("Running command via ssh:" + command);

            StringBuilder output = new StringBuilder();

            Channel channel = session.openChannel("exec");
            ((ChannelExec) channel).setCommand(command);

            channel.setInputStream(null);
            //((ChannelExec) channel).setErrStream(System.err);

            InputStream in = channel.getInputStream();

            channel.connect();

            byte[] tmp = new byte[1024];
            while (true) {
                while (in.available() > 0) {
                    int i = in.read(tmp, 0, 1024);
                    if (i < 0) break;
                    String read = (new String(tmp, 0, i));
                    output.append(read);
                    log.debug(read);
                }
                if (channel.isClosed()) {
                    log.debug("exit-status: " + channel.getExitStatus());
                    break;
                }
                try {
                    Thread.sleep(1000);
                } catch (Exception ee) {
                }
            }
            channel.disconnect();
            return output.toString();
        }
        catch (Exception e) {
            log.error("Error while running command via ssh", e);
            return null;
        }
    }

    public void close() {
        if(session != null && session.isConnected()) {
            session.disconnect();
        }
    }
}
